import logging
from rest_framework import serializers
from django.db import transaction

from goods.models import SKU, GoodsCategory, SPUSpecification, SpecificationOption, SKUSpecification
from celery_tasks.detail_static.tasks import generate_static_sku_detail_html

logger = logging.getLogger('django')


class SKUSpecificationSerializer(serializers.ModelSerializer):
    pass


class SKUSerializer(serializers.ModelSerializer):
    spu_id = serializers.IntegerField()
    category_id = serializers.IntegerField()

    class Meta:
        model = SKU
        fields = '__all__'
        read_only_fields = ('category', 'spu')

    def create(self, validated_data):
        specs = self.context['request'].data.get('specs')

        # 开启事务
        with transaction.atomic():
            # 设置保存点
            save_point = transaction.savepoint()

            try:
                # 保存sku信息
                sku = SKU.objects.create(**validated_data)
                # 保存sku规格信息
                for spec in specs:
                    SKUSpecification.objects.create(spec_id=spec['spec_id'], option_id=spec['option_id'], sku=sku)
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError('保存失败')
            else:
                transaction.savepoint_commit(save_point)
                # 创建商品完成，异步更新静态化页面
                generate_static_sku_detail_html.delay(sku.id)
                # 返回结果
                return sku


class GoodsCategorySerializer(serializers.ModelSerializer):
    """
        商品分类序列化器
    """
    class Meta:
        model = GoodsCategory
        fields = '__all__'


class SpecificationOptionSerializer(serializers.ModelSerializer):
    """
        商品规格选项序列化器
    """
    class Meta:
        model = SpecificationOption
        fields = '__all__'


class SPUSpecificationSerializer(serializers.ModelSerializer):
    """
        商品规格序列化器
    """
    # 做嵌套序列化返回
    options = SpecificationOptionSerializer(many=True)  # 这是在模型类中指定了规格选项子表的外检别名是option，所以可以直接用option变量接收
    # specification_set = SpecificationOptionSerializer(many=True)  # 如果不指明外键的别名，必须用子表明_set来指定

    spu = serializers.StringRelatedField(read_only=True)
    spu_id = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = SPUSpecification
        fields = '__all__'
